/*
 * cirLinkedList.c
 *
 *  Created on: Nov 10, 2011
 *      Author: dpguimaraes
 */

#include "cirLinkedList.h"

//sets current node to next node
void nextNode(CirList *pMyList) {
	pMyList->pCurrentNode = pMyList->pCurrentNode->pNextNode;
}

//sets current node to prev node
void prevNode(CirList *pMyList) {
	pMyList->pCurrentNode = pMyList->pCurrentNode->pPrevNode;
}

/**
 * This method adds a node to list. The list and a contact are passed in,
 * then this method creates a Node pointer and mallocs space. The node is
 * then inserted into the list after current and sets current to the new
 * Node. If there are no nodes, then the method assigns both Top and
 * Current to the new node.
 */
void add(CirList *pMyList, Contact *pContact) {
	Node *newNode = malloc(sizeof(Node)); //new node to be inserted into list

	newNode->pCurrentContact = pContact;

	//set current prev and next node to the new contact add node to the list
	if (pMyList->numNodes == 0) {
		newNode->pPrevNode = newNode;
		newNode->pNextNode = newNode;

		pMyList->pCurrentNode = newNode;
		pMyList->pTopNode = newNode;
	}

	//insert after the current node
	else {
		//set node pointers of the new node
		newNode->pPrevNode = pMyList->pCurrentNode;
		newNode->pNextNode = pMyList->pCurrentNode->pNextNode;

		//set next and prev pointer of the prev and next node
		pMyList->pCurrentNode->pNextNode = newNode;
		newNode->pNextNode->pPrevNode = newNode;

		pMyList->pCurrentNode = newNode;
	}
	pMyList->numNodes++;
}

/**
 * This method deletes the current node in the list. It moves current to the next node.
 * This method returns 1 after deleting a node. It returns 0 if there is no node to
 * delete.
 */
int delete(CirList *pMyList) {
	if (pMyList->numNodes != 0) {
		Node *pNodeToDelete = pMyList->pCurrentNode; //node to be deleted
		Contact *pContactToDelete = (pMyList->pCurrentNode)->pCurrentContact; //contact to be deleted

		//change pointers of the next and prev pointer of the prev and pNextNode node
		pMyList->pCurrentNode->pPrevNode->pNextNode =
				pMyList->pCurrentNode->pNextNode;
		pMyList->pCurrentNode->pNextNode->pPrevNode =
				pMyList->pCurrentNode->pPrevNode;

		//if the current node is the top node, increment the top node
		if (pMyList->pTopNode == pMyList->pCurrentNode)
			pMyList->pTopNode = pMyList->pTopNode->pNextNode;

		//increment the current pointer
		pMyList->pCurrentNode = pMyList->pCurrentNode->pNextNode;

		pMyList->numNodes--;

		free(pNodeToDelete);
		free(pContactToDelete);

		return DELETE_SUCCESS;
	}

	return EMPTY_LIST;
}

/**
 * This method modifies the current contact with the data provided. The 3rd var is to specify which piece needs
 * to be replaced.
 */
int edit(CirList *pMyList, char *editedData, int dataIndex) {
	switch (dataIndex) {
	case FIRST:
		strcpy(pMyList->pCurrentNode->pCurrentContact->firstName, editedData);
		return EDIT_SUCCESS;
	case LAST:
		strcpy(pMyList->pCurrentNode->pCurrentContact->lastName, editedData);
		return EDIT_SUCCESS;
	case EMAIL_ONE:
		strcpy(pMyList->pCurrentNode->pCurrentContact->emailOne, editedData);
		return EDIT_SUCCESS;
	case EMAIL_TWO:
		strcpy(pMyList->pCurrentNode->pCurrentContact->emailTwo, editedData);
		return EDIT_SUCCESS;
	}

	return OUT_OF_RANGE;
}

/**
 * This method takes a list and a last name. It then seeks that name in the list.
 * The method asumes the list is unordered. It will scroll forward and compare
 * each contact in the list once. If it finds the contact, it will set that node
 * to the current node and return a 1. If not found it will return a 0 and do
 * nothing with the current node.
 */
int search(CirList *pMyList, char *lastName) {
	int i;

	for (i = 0; i <= pMyList->numNodes; i++) {
		if (strcmp(pMyList->pCurrentNode->pCurrentContact->lastName, lastName)
				== 0)
			return FOUND;

		else
			nextNode(pMyList);
	}

	return NOT_FOUND;
}

/**
 * This method sorts the contacts in the list by last name. It will set Top to the first name aphabetically.
 * The sort is a selection sort.
 */
void sort(CirList *pMyList) {
	int i, j; //interators
	Node *pSwap; //A marker for the node that we are comparing against
	Node *pSmallestNode; //A marker for the current small contact

	pMyList->pTopNode = findFirst(pMyList); //Top is now sorted
	pMyList->pCurrentNode = pMyList->pTopNode->pNextNode;
	pSmallestNode = pMyList->pCurrentNode;
	pSwap = pMyList->pCurrentNode;

	nextNode(pMyList);

	for (i = 1; i < pMyList->numNodes; i++) {
		for (j = i; j < pMyList->numNodes; j++) {
			if (strcmp(pMyList->pCurrentNode->pCurrentContact->lastName,
					pSmallestNode->pCurrentContact->lastName) < 0)
				pSmallestNode = pMyList->pCurrentNode;

			nextNode(pMyList);
		}
		if (strcmp(pSmallestNode->pCurrentContact->lastName,
				pSwap->pCurrentContact->lastName) < 0)
			swap(pSmallestNode, pSwap);
		pSwap = pSwap->pNextNode;
		pMyList->pCurrentNode = pSwap->pNextNode;
	}
	nextNode(pMyList);//make current wrap around to the front
}

/**
 * Finds the alphanumericaly first contact and returns the node containg that contact
 */
Node *findFirst(CirList *pMyList) {
	Node *pFirst = pMyList->pCurrentNode; //assume current is already first
	int i;

	for (i = 0; i < pMyList->numNodes; i++) {
		nextNode(pMyList);
		if (strcmp(pMyList->pCurrentNode->pCurrentContact->lastName,
				pFirst->pCurrentContact->lastName) < 0)
			pFirst = pMyList->pCurrentNode;
	}

	return pFirst;
}

/**
 * Swaps the contacts of two nodes.
 */
void swap(Node *node1, Node *node2){
	Contact *pTempContact;

	pTempContact = node1->pCurrentContact;
	node1->pCurrentContact = node2->pCurrentContact;
	node2->pCurrentContact = pTempContact;
}
